from uo_order import UOOrder  # Import Order class
from config import Bounds, ItemIDs

class UOItems:
    """A wrapper class for RAE's Items module."""
    
    @staticmethod
    def FindByIDAndName(item_id, container_serial, name):
        """Find the first item matching the given item ID and name.
        
        Args:
            item_id: The item ID to search for
            container_serial: The container to search in (-1 for any item)
            name: The name to filter items by (checks item properties)
            
        Returns:
            Item or None: The first matching item or None if not found
        """
        # Call RAE's FindAllByID with default values:
        # color = -1 (any color)
        # depth = 0 (top level only)
        # consider_ignore_list = True (exclude ignored items)
        items = Items.FindAllByID(item_id, -1, container_serial, 0, True)
        
        #print(f"Found {len(items)} items with ID {item_id}")
        
        # Find the first item matching both ID and name
        for item in items:
            # Get item properties
            props = Items.GetPropStringList(item.Serial)
            #print(f"Item properties: {props}")
            
            # Check if any property contains the name
            if any(name.lower() in prop.lower() for prop in props):
                return item
                
        return None
        
    @staticmethod
    def FindAllByID(item_id, container_serial):
        """Find all items with the specified ID in a container.
        
        Args:
            item_id: The item ID to search for
            container_serial: The container to search in (-1 for any container)
            
        Returns:
            list: List of all found items, or empty list if none found
        """
        # Directly use RAE's FindAllByID API with default values:
        # color = -1 (any color)
        # depth = 0 (top level only)
        # consider_ignore_list = True (exclude ignored items)
        return Items.FindAllByID(item_id, -1, container_serial, 0, True)
        
    @staticmethod
    def GetPropStringList(serial):
        """Get property strings for an item.
        
        Args:
            serial: The item's serial number
            
        Returns:
            list: List of property strings
        """
        return Items.GetPropStringList(serial)
        
    @staticmethod
    def Move(serial, target_serial, amount=0):
        """Move an item to a target container.
        
        Args:
            serial: The item's serial number
            target_serial: The target container's serial number
            amount: Amount to move (0 for all)
            
        Returns:
            bool: True if move was successful
        """
        return Items.Move(serial, target_serial, amount)
        
    @staticmethod
    def UseItem(serial):
        """Use an item.
        
        Args:
            serial: The item's serial number
            
        Returns:
            bool: True if use was successful
        """
        return Items.UseItem(serial)
        
    @staticmethod
    def FindNearestByID(item_ids):
        """
        Find the nearest item with the specified ID or IDs.
        Args:
            item_ids: int or list of int
        Returns:
            Item or None: The nearest item found or None if not found
        """
        if isinstance(item_ids, int):
            # Original implementation for a single ID
            filter = Items.Filter()
            filter.Enabled = True
            filter.OnGround = True
            filter.Graphics.Add(item_ids)
            items = Items.ApplyFilter(filter)
            if not items:
                return None
            return Items.Select(items, "Nearest")

        elif isinstance(item_ids, list):
            nearest = None
            min_dist = float('inf')
            for item_id in item_ids:
                item = UOItems.FindNearestByID(item_id)  # Recursive call
                if item:
                    dist = Player.DistanceTo(item)
                    if dist < min_dist:
                        nearest = item
                        min_dist = dist
            return nearest

        else:
            raise TypeError("item_ids must be int or list of int")
        
    @staticmethod
    def IsInRange(bounds):
        """Check if the player is within the specified bounds.
        
        Args:
            bounds: A dictionary containing the area boundaries with keys:
                   'min_x', 'max_x', 'min_y', 'max_y', 'min_z'
            
        Returns:
            bool: True if player is within bounds, False otherwise
        """
        # Get player's current position
        x = Player.Position.X
        y = Player.Position.Y
        z = Player.Position.Z
        
        # Check if player is within the bounds
        return (bounds['min_x'] <= x <= bounds['max_x'] and
                bounds['min_y'] <= y <= bounds['max_y'] and
                z == bounds['min_z'])  # Z coordinate must match exactly 
    
    @staticmethod
    def GetPropValue(serial, property_name):
        """Get the value of a specific property for an item.
        
        Args:
            serial: The item's serial number
            property_name: The name of the property to get
            
        Returns:
            The value of the property, or None if not found
        """
        return Items.GetPropValue(serial, property_name)
        
    @staticmethod
    def BackpackCount(item_id):
        """Get the total number of items in the player's backpack and its containers.
        
        Args:
            item_id: The ID of the item to count
            
        Returns:
            int: Total number of items found in the backpack and its containers
        """
        return Items.BackpackCount(item_id, -1)  # -1 for any color
    
    @staticmethod
    def PutIntoTrashBarrel(trash_barrel):
        """Put specified items from backpack into trash barrel
        
        Args:
            trash_barrel: The trash barrel Item object to put items into
        """
        # Define mining trash item IDs
        MINING_TRASH_ITEMS = [
            0x0F39,  # Sturdy Shovel
            0x0E85,  # A Gargoyle's Pickaxe
            0x0E86,  # Sturdy Pickaxe
            0x0FB4,  # Prospector's Tool
            0x13C6,  # Mining Gloves +1
            0x13D5,  # Mining Gloves +3
            0x13EB,  # Mining Gloves +5
            #0x1006   # Powder of Enhancement
        ]
        
        if not trash_barrel:
            print("No trash barrel provided")
            return
            
        # Find all trash items in backpack
        total_items = 0
        for item_id in MINING_TRASH_ITEMS:
            items = Items.FindAllByID(item_id, -1, Player.Backpack.Serial, True)
            if not items:
                continue
                
            # Move each item to trash barrel
            for item in items:
                Items.Move(item.Serial, trash_barrel.Serial, item.Amount)
                Misc.Pause(800)  # Wait for move to complete
                total_items += 1
                
        if total_items > 0:
            print(f"Successfully put {total_items} items into trash barrel")
        else:
            print("No items found in backpack to trash")


    @staticmethod
    def PutIntoBank(items_to_store):
        """
        Put valuable items from backpack into bank
        
        Args:
            items_to_store: List of item IDs to store in bank
        """
        # Open bank
        Player.ChatSay(52, "bank")
        Misc.Pause(1000)  # Wait for bank to open
        
        # Find all items in backpack
        total_items = 0
        items = Items.FindAllByID(items_to_store, -1, Player.Backpack.Serial, True)
        # Move all items to bank
        for item in items:
            Items.Move(item.Serial, Player.Bank.Serial, item.Amount)
            Misc.Pause(800)  # Wait for move to complete
            total_items += 1
                
        print(f"Put {total_items} items into bank")

    @staticmethod
    def ParseOrderProperties(orders):
        """Get the value of a specific property for an item.
        
        Returns:
            list: List of all found order objects with their value analysis
        """
        
        # Use Items.FindAll to find bulk orders in backpack
        found_orders = []
        
        if not orders:
            print("No orders found")
            return found_orders
        
        for order_item in orders:
            # Get order properties
            props = Items.GetPropStringList(order_item.Serial)
            #print(f"\nOrder Item Properties:")
            #for prop in props:
            #    print(f"  {prop}")
            
            # Create new order object, capitalize first letter of name
            order = UOOrder(name=order_item.Name.title())  # Use title() to capitalize first letter of each word
            order.serial = order_item.Serial
            required_amount = 0  # Store amount to make value
            
            # Parse order properties
            for prop in props:
                prop_lower = prop.lower().strip()

                if "blessed" in prop_lower:
                    order.is_blessed = True
                elif "weight:" in prop_lower:
                    order.weight = int(prop_lower.split(":")[1].strip().split()[0])
                elif "small bulk order" in prop_lower:
                    order.size = "Small"
                elif "large bulk order" in prop_lower:
                    order.size = "Large"
                elif "all items must be exceptional" in prop_lower:
                    # Only set to Exceptional when explicitly specified
                    order.quality_requirement = "Exceptional"  
                elif "all items must be made with" in prop_lower:
                    # Only set material type when explicitly specified
                    material = prop_lower.split("with")[1].strip().replace("ingots.", "ingots")
                    order.material_requirement = material.title()  # Capitalize first letter
                elif "amount to make:" in prop_lower:
                    required_amount = int(prop_lower.split(":")[1].strip())
                # Check item type and completed amount
                elif ":" in prop_lower:
                    item_name, amount = prop_lower.split(":")
                    item_name = item_name.strip()
                    if item_name and item_name not in [ "blessed", "weight", "amount to make"]:
                        amount_str = amount.strip()
                        if amount_str.isdigit():
                            completed_amount = int(amount_str)
                            order.add_required_item(
                                item_name=item_name.title(),  # Capitalize first letter
                                required_amount=required_amount,
                                completed_amount=completed_amount
                            )
            
            # Check if order is completed
            order.is_completed = all(item['completed'] >= item['amount'] for item in order.required_items)
            
            # Analyze order type and set it
            order.analyze_type()
            
            found_orders.append(order)
            #print(order)
            
        #print(f"Total orders found: {len(found_orders)}")
        return found_orders
